package convert;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;

import main.Common;
import main.Def;
import main.ErrorDefine;
import main.ErrorException;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

import config.Config;
import config.EConfig;

public class EWorkBook extends BaseContent
{
	private String m_dirPath;
	private Workbook m_workBook;
	private String m_configSheet;
	private boolean m_isExcel07;
	private ArrayList<ESheet> m_configSheets;
	private String m_wholePath;
	private Element m_xmlRoot;
	
	public static BaseContent m_root = new BaseContent("", null);
	
	public EWorkBook(String fileName, String configSheet) throws ErrorException
	{
		super(main.Common.getNameWithoutExtented(fileName), m_root);
		m_wholePath = fileName;
		m_configSheet = configSheet;
		m_dirPath = Common.getPath(fileName);
		m_isExcel07 = isExcel07(fileName);
		readExcel(fileName);
		m_root.addChild(this);
	}
	
	private boolean isExcel07(String name)
	{
		return name.indexOf(Def.EXCELL_07) != -1;
	}
	
	public boolean isExcel07()
	{
		return m_isExcel07;
	}
	
	public Element getXmlNode()
	{
		return m_xmlRoot;
	}
	
	public Workbook getRealWorkbook()
	{
		return m_workBook;
	}
	
	private void readExcel(String name) throws ErrorException
	{
		FileInputStream fis = null;
		try 
		{
			fis = new FileInputStream(name);
			m_workBook = m_isExcel07? new XSSFWorkbook(fis): new HSSFWorkbook(fis);
		} 
		catch(Exception e) 
		{
			throw new ErrorException(ErrorDefine.E_CANT_READ_EXCEL_ERR, name);
		}
		finally
		{
			if(fis != null)
			{
				try 
				{
					fis.close();
				} 
				catch(Exception e2) 
				{
				}
			}
		}
	}
	
	public void init()
	{
		EFormula.setWorkbook(this);
		m_configSheets = new ArrayList<>();
		int len = m_workBook.getNumberOfSheets();
		for(int i = 0; i < len; ++i)
		{	
			Sheet s = m_workBook.getSheetAt(i);
			String name = s.getSheetName();
			if(hasChild(name) != null)
			{
				Common.print("duplicate sheet " + name);
			}
			ESheet sheet = new ESheet(s, this);
			if(isConfigSheet(name))
			{
				sheet.initConfig();
				m_configSheets.add(sheet);
			}
			else 
			{
				sheet.init();
				addChild(sheet);	
			}
		}
		EFormula.clear();
	}
	
	private boolean isConfigSheet(String name)
	{
		int len = m_configSheet.length();
		if(name.length() >= len)
		{
			name = name.substring(0, len);
			return name.compareTo(m_configSheet) == 0;
		}
		return false;
	}
	
	public void applyConfig() throws ErrorException
	{
		for(ESheet sheet: m_configSheets)
		{
			ArrayList<EConfig> list = sheet.getConfigs();
			for(EConfig ec: list)
			{
				ec.applyConfig();
			}
		}
	}
	
	public static EWorkBook getExcel(String name, int index) throws ErrorException
	{
		return (EWorkBook)m_root.getChild(name, index);
	}
	
	public static EWorkBook getExcel(String name) throws ErrorException
	{
		return (EWorkBook)m_root.getChild(name);
	}
	
	public Element toXml() throws ErrorException
	{
		if(m_xmlRoot != null)
		{
			return m_xmlRoot;
		}
		try 
		{
			if(EConfig.m_isSimpleFormat)
			{
				m_xmlRoot = new Element(m_name);
			}
			else 
			{
				m_xmlRoot = new Element(Def.EXCEL);
				m_xmlRoot.setAttribute(Def.NAME, m_name);
			}
			if(m_children != null)
			{
				for(BaseContent bc: m_children)
				{
					ESheet sh = (ESheet)bc;
					if(!EConfig.m_ignoreSheets.containsKey(sh.getName()))
					{
						sh.toXml(m_xmlRoot);
					}
				}
			}
			return m_xmlRoot;
		}
		catch(Exception e) 
		{
			throw new ErrorException(ErrorDefine.E_TO_XML_ERR, e.getMessage());
		}
	}
	
	public String getDirPath()
	{
		return m_dirPath;
	}
	
	public void saveToXml() throws ErrorException
	{
		saveToXml(m_xmlRoot, m_dirPath + m_name + ".xml");
	}
	
	public static void saveToXml(Element root, String path) throws ErrorException
	{
		if(root != null)
		{
			XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
			FileOutputStream fos = null;
			OutputStreamWriter writer = null;
			try 
			{
				fos = new FileOutputStream(path);
				writer = new OutputStreamWriter(fos, "utf-8");
				outputter.output(root, writer);
			}
			catch(Exception e)
			{
				throw new ErrorException(ErrorDefine.E_CANT_WRITE_XML_ERR, path);
			}
			finally
			{
				if(writer != null)
				{
					try 
					{
						writer.close();
						fos.close();
					}
					catch(Exception e2) 
					{
					}
				}
			}
		}
	}
	
	public void addConfigSheet()
	{
		String sheetName = Def.DEFAULT_CONFIG;
		int index = 0;
		while(m_workBook.getSheet(sheetName) != null) 
		{
			sheetName += index++;
		}
		Sheet sheet = m_workBook.createSheet(sheetName);
		index = 0;
		for(Config cg: Config.values())
		{
			Row row = sheet.createRow(index);
			Cell cell = row.createCell(0);
			cell.setCellValue(cg.getText());
			cell = row.createCell(1);
			cell.setCellValue(cg.getDefault());
			++index;
		}
	}
	
	public void saveToExcel() throws ErrorException
	{
		FileOutputStream fos = null;
		try 
		{
			fos = new FileOutputStream(m_wholePath);
			m_workBook.write(fos);
		}
		catch (Exception e) 
		{
			throw new ErrorException(ErrorDefine.E_CANT_WRITE_EXCEL_ERR, m_wholePath);
		}
		finally
		{
			if(fos != null)
			{
				try 
				{
					fos.close();
				}
				catch(Exception e2) 
				{
				}
			}
		}
	}
	
	/*public void fromXml() throws ErrorException
	{
		String path = m_dirPath + m_name + ".xml";
		XmlDoc doc = new XmlDoc(path);
		XmlNode node = doc.getRoot();
		for(int i = 0, size = node.getChildNumber(); i < size; ++i)
		{
			XmlNode temp = node.getChild(i);
			String name = temp.getAttribute(Def.VALUE);

			m_workBook.addSheet(name);
			ESheet tab = new ESheet(m_workBook.getSheet(name), this);
			tab.fromXml(temp);
		}
	}
	
	public void complie() throws ErrorException
	{
		if(m_children != null)
		{
			for(BaseContent bc: m_children)
			{
				if(bc.getClass() == ScriptTable.class)
				{
					ScriptTable st = (ScriptTable)bc;
					st.complie();
				}
			}
		}
	}
	
	public void output() throws ErrorException
	{
		if(m_children != null)
		{
			m_currentExcel = this;
			for(BaseContent bc: m_children)
			{
				if(bc.getClass() == ScriptTable.class)
				{
					ScriptTable st = (ScriptTable)bc;
					st.output();
				}
			}
		}
	}*/
}
